package com.yingxin.yx.framework.security.user;


import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.yingxin.yx.framework.commons.constant.ServiceType;
import com.yingxin.yx.framework.commons.exception.BizException;
import com.yingxin.yx.framework.commons.helper.PropertiesHelper;
import com.yingxin.yx.framework.user.core.CompanyConst;
import com.yingxin.yx.framework.user.core.IUserSupport;
import com.yingxin.yx.framework.user.dto.OnLineUser;
import com.yingxin.yx.framework.user.dto.UserDto;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author fanchao
 */
@Component
public class UserSupport implements IUserSupport {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public UserDto getUser() {
        PrincipalDto principal = null;
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication.getPrincipal() != null) {
                principal = (PrincipalDto) authentication.getPrincipal();
            }
        } catch (Exception ignored) {
        }
        if (principal == null) {
            return THREAD_USER.get();
        }
        return principal;
    }

    public String getUsersCacheKey(){
        String serviceType = PropertiesHelper.getInstance().getProperty("serviceType");
        if(ServiceType.app.equals(serviceType)){
            return getAppUsersCacheKey();
        } else if (ServiceType.pc.equals(serviceType)){
            return getPcUsersCacheKey();
        }else {
            return getOpenApiUsersCacheKey();
        }
    }

    public String getPcUsersCacheKey(){
        return PropertiesHelper.getInstance().getProperty("pcUsersCache");
    }

    public String getAppUsersCacheKey(){
        return PropertiesHelper.getInstance().getProperty("appUsersCache");
    }
    public String getOpenApiUsersCacheKey(){
        return PropertiesHelper.getInstance().getProperty("openApiUsersCache");
    }

    @Override
    public UserDto getUser(String userId) {
        String key = getUsersCacheKey();
        return getUser(userId, key);
    }

    public UserDto getUser(String userId, String key) {
        Object obj = redisTemplate.opsForHash().get(key, userId);
        if (obj == null) {
            return null;
        }
        PrincipalDto principal = JSON.parseObject(obj.toString(), PrincipalDto.class);
        if (principal == null) {
            return null;
        }
        return principal;
    }

    @Override
    public void putUser(UserDto user) {
        PrincipalDto principal = (PrincipalDto) user;
        redisTemplate.opsForHash().put(getUsersCacheKey(), principal.getUserId(), JSON.toJSONString(principal));
    }

    @Override
    public void kickOutUser(String userId) {
        // pc 查看是否已经登录，已经登录就踢出
        kickOutUser(userId, getPcUsersCacheKey());
        // app 查看是否已经登录，已经登录就踢出
        kickOutUser(userId, getAppUsersCacheKey());
        // openApi 查看是否已经登录，已经登录就踢出
        kickOutUser(userId, getOpenApiUsersCacheKey());
    }

    /**
     * 强制退出
     * @param userId
     * @param type
     */
    @Override
    public void forceOutUser(String userId, String type) {
        if (type.equals("PC")){
            kickOutUser(userId,getPcUsersCacheKey());
        }
        if (type.equals("APP")){
            kickOutUser(userId,getAppUsersCacheKey());
        }
    }

    public void kickOutUser(String userId, String key){
        Object user = redisTemplate.opsForHash().get(key, userId);
        if (user != null) {
            redisTemplate.opsForHash().delete(key, userId);
        }
    }

    @Override
    public String getUserId() {
        UserDto user = getUser();
        if (user == null) {
            return null;
        }
        return user.getUserId();
    }

    @Override
    public String getStaffName() {
        UserDto user = getUser();
        if (user == null) {
            return null;
        }
        return user.getStaffName();
    }

    @Override
    public void activateReloadPermissions() {
        // pc
        Set<Object> pcSet = redisTemplate.opsForHash().keys(getPcUsersCacheKey());
        // app
        Set<Object> appSet = redisTemplate.opsForHash().keys(getAppUsersCacheKey());
        // openApi
        Set<Object> openApiSet = redisTemplate.opsForHash().keys(getOpenApiUsersCacheKey());

        pcSet.addAll(appSet);
        pcSet.addAll(openApiSet);
        for (Object userId : pcSet) {
            activateReloadPermissionsByUser((String) userId);
        }
    }

    @Override
    public void activateReloadPermissionsByUser(String userId) {
        // pc
        activateReloadPermissionsByUser(userId, getPcUsersCacheKey());
        // app
        activateReloadPermissionsByUser(userId, getAppUsersCacheKey());
        // openApi
        activateReloadPermissionsByUser(userId, getOpenApiUsersCacheKey());
    }

    public void activateReloadPermissionsByUser(String userId, String key) {
        UserDto user = getUser(userId, key);
        if (user != null) {
            redisTemplate.opsForHash().put(key + "_reloadPermissions", userId, userId);
        }
    }

    @Override
    public Boolean isReloadPermissions(String userId) {
        String key = getUsersCacheKey() + "_reloadPermissions";
        Boolean b = redisTemplate.opsForHash().hasKey(key, userId);
        if (b) {
            Long l = redisTemplate.opsForHash().delete(key, userId);
        }
        return b;
    }

    @Override
    public Boolean hasRole(String role) {
        UserDto user = getUser();
        if (user == null) {
            return false;
        }
        if (user.getRoleSet() == null) {
            return false;
        }
        return user.getRoleSet().contains(role);
    }

    @Override
    public Boolean hasPermission(String permission) {
        UserDto user = getUser();
        if (user == null) {
            return false;
        }
        if (user.getResourceSet() == null) {
            return false;
        }
        return user.getResourceSet().contains(permission);
    }

    @Override
    public String viewBy(String permission) {
        return hasPermission(permission) ? null : getUserId();
    }

    @Override
    public Boolean checkUserPermission(String permission) {
        return hasPermission(permission);
    }

    @Override
    public List<String> getAuthCompanyIds() {
        UserDto user = getUser();
        if (user == null) {
            throw new BizException("没有相关厂区的数据权限");
        }
        if (user.getResourceSet() == null) {
            throw new BizException("没有相关厂区的数据权限");
        }
        List<String> companyIds = new ArrayList<>();
        if (user.getResourceSet().contains(CompanyConst.HT_PERM)) {
            companyIds.add(CompanyConst.HT_ID);
        }
        if (user.getResourceSet().contains(CompanyConst.XT_PERM)) {
            companyIds.add(CompanyConst.XT_ID);
        }
        if (user.getResourceSet().contains(CompanyConst.YX_PERM)) {
            companyIds.add(CompanyConst.YX_ID);
        }
        if (CollectionUtil.isEmpty(companyIds)) {
            throw new BizException("没有相关厂区的数据权限");
        }
        return companyIds;
    }

    @Override
    public void checkAuthCompany(String companyId) {
        List<String> companyIds = getAuthCompanyIds();
        if (!companyIds.contains(companyId)) {
            if (CompanyConst.HT_ID.equals(companyId)) {
                throw new BizException("没有华泰厂区的数据权限");
            } else if (CompanyConst.XT_ID.equals(companyId)) {
                throw new BizException("没有鑫泰厂区的数据权限");
            } else if (CompanyConst.YX_ID.equals(companyId)) {
                throw new BizException("没有盈鑫厂区的数据权限");
            } else {
                throw new BizException("没有相关厂区的数据权限");
            }
        }
    }

    //    @Override
    //    public LicenseResult checkLicense() {
    //        LicenseVerifyManager licenseVerifyManager = new LicenseVerifyManager();
    //        LicenseResult verifyResult = licenseVerifyManager.verify(properties.getVerifyParam());
    //        return verifyResult;
    //    }

    /**
     * 获取所有登录在线用户
     * @return
     */
    @Override
    public List<OnLineUser> getPCLoginUser(Map<String,String> map){
        String userIdQ = map.get("userId");
        ArrayList<OnLineUser> userLoginList = new ArrayList<>();
        if (StringUtils.isEmpty(userIdQ)){
            Set<Object> keys = redisTemplate.opsForHash().keys(getPcUsersCacheKey());
            for (Object userId : keys) {
                OnLineUser onLineUser = new OnLineUser();
                UserDto user = getUser((String) userId,getPcUsersCacheKey());
                BeanUtils.copyProperties(user,onLineUser);
                userLoginList.add(onLineUser);
            }
        }else {
            OnLineUser onLineUser = new OnLineUser();
            UserDto user = getUser((String) userIdQ);
            if (user != null){
                BeanUtils.copyProperties(user,onLineUser);
                userLoginList.add(onLineUser);
            }
        }
        return userLoginList;
    }
    @Override
    public List<OnLineUser> getAppLoginUser(Map<String,String> map){
        String userIdQ = map.get("userId");
        ArrayList<OnLineUser> userLoginList = new ArrayList<>();
        if (StringUtils.isEmpty(userIdQ)){
            Set<Object> keys = redisTemplate.opsForHash().keys(getAppUsersCacheKey());
            for (Object userId : keys) {
                OnLineUser onLineUser = new OnLineUser();
                UserDto user = getUser((String) userId,getAppUsersCacheKey());
                if (user != null){
                    BeanUtils.copyProperties(user,onLineUser);
                    userLoginList.add(onLineUser);
                }
            }
        }else {
            OnLineUser onLineUser = new OnLineUser();
            UserDto user = getUser((String) userIdQ,getAppUsersCacheKey());
            if (user != null){
                BeanUtils.copyProperties(user,onLineUser);
                userLoginList.add(onLineUser);
            }
        }
        return userLoginList;
    }
}